/*
 * Copyright © 2017 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */

package cn.hermit.nio.http.server;

import cn.hermit.nio.http.Http;
import cn.hermit.nio.http.HttpException;
import cn.hermit.util.IOUtils;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author JackGao 高建国
 * @description //TODO 设计说明
 * @date 2/6/2017
 */
public class ResourceHttpHandler implements HttpHandler, Http {

    private static final Logger logger = Logger.getLogger(ResourceHttpHandler.class.getName());


    private static final DateFormat formater = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);

    static {
        formater.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    private volatile String staticRoot = "";

    @Override
    public void handle(HttpRequest request, HttpResponse response) throws HttpException {

        String requestURI = request.getRequestURI();
        String file = null;
        File currentFile = null;
        Date lastModified;
        String acceptEncoding;
        URL url = null;
        try {
            if (staticRoot.startsWith("classpath:")) {
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                String resourceName = staticRoot.substring(10) + requestURI;
                url = loader.getResource(resourceName);
                file = url.getFile();
                currentFile = new File(file);
            } else {
                file = staticRoot + requestURI;
                currentFile = new File(file);
            }
            String mime = new MimetypesFileTypeMap().getContentType(currentFile);
            acceptEncoding = request.getHeader(ACCEPT_ENCODING);
            // gzip text
            boolean zip = mime.contains("text") && acceptEncoding != null
                    && (acceptEncoding.contains("gzip") || acceptEncoding.contains("gzip"));
            ResourceSoftCache.CacheEntry entry = null;
            if (zip) {
                entry = ResourceSoftCache.getInstance().get(file + GZIP);
            } else {
                entry = ResourceSoftCache.getInstance().get(file);
            }
            // miss the cache
            if (entry == null) {
                response.clear(); // getHttpRequest ready for next request;

                logger.info("miss the cache " + file);

                // always keep alive
                response.addHeader(CONNECTION, KEEP_ALIVE);
                response.addHeader(CONTENT_TYPE, mime);

                // response responseBody byte, exception throws here
                if (url == null) {
                    response.setBody(IOUtils.file2ByteArray(currentFile, zip));
                } else {
                    response.setBody(IOUtils.url2ByteArray(url, zip));
                }

                response.addHeader(CONTENT_LENGTH, response.getBody().length);
                if (zip) {
                    // add zip request
                    response.addHeader(CONTENT_ENCODING, GZIP);
                }

                // last modified request
                lastModified = new Date(currentFile.lastModified());
                response.addHeader(LAST_MODIFIED, formater.format(lastModified));

                // add to the cache
                if (zip)
                    file = file + GZIP;
                ResourceSoftCache.getInstance().put(file, response.getHeaderBytes(), response.getBody());
            }
            // cache is hit
            else {
                logger.fine("cache is hit" + file);
                response.setBody(entry.body);
                response.setHeaderBytes(entry.header);
            }
        } catch (IOException e) {
            response.addHeader(CONTENT_LENGTH, 0);
            response.setStatus(NOT_FOUND_404);
            // cache 404 if case client make a mistake again
            ResourceSoftCache.getInstance().put(file, response.getHeaderBytes(), response.getBody());
            logger.log(Level.SEVERE, "404 error", e);
        }
    }

    public void setStaticRoot(String staticRoot) {
        this.staticRoot = staticRoot;
    }
}
